---------------------------------------------------------------
-- @Description：         manage robot
---------------------------------------------------------------
local skynet = require "skynet"
require "skynet.manager"
local log = require "sky_log"
local cc = require "sky_call"
local nn = require "sky_node"
local queue = require "skynet.queue"
local Queue = queue()
require "def"

local M = {
    watchdog = nil,
    t_use_robots = {},
}

--============================= Local Function =============================--
local function fill_robot_info(robots, platid, svid, tid, buy_min, num)    
    platid = tonumber(platid)
    svid = tonumber(svid)
    tid = tonumber(tid)
    num = tonumber(num)
    buy_min = tonumber(buy_min)

    local server_config = cc.call_config("get_server_config", platid, svid, tid)
    if not server_config then 
        log.error("get_server_config error!")
    end
    --log.info("server_config=", server_config)

    local server_ip = (server_config or {}).server_ip
    local server_port = (server_config or {}).server_port
    local tables = (server_config or {}).tables or {}
    local buy_max = (tables[tid] or {}).buy_max
    local solevel = (tables[tid] or {}).solevel
    local table_type = (tables[tid] or {}).table_type
    local big_blind = (tables[tid] or {}).big_blind

    local robot_ids_t
    if table_type==TABLE_TYPE.TARNEEB then
        robot_ids_t = cc.call_config("get_robot_id_tarneeb", platid, num, tonumber(big_blind))
    else
        robot_ids_t = cc.call_config("get_robot_id", platid, buy_min, num)
    end

    if #robot_ids_t~=#robots then
        log.error("fill_robot_by_tid error! #robots="..#robots.." #robot_ids_t="..#robot_ids_t)
    end

    for _, v in pairs(robots) do
        local t = table.remove(robot_ids_t or {})
        v.config_info = {
            platid = platid,
            svid = svid,
            tid = tid,
            buy_min = tonumber(buy_min),
            buy_max = tonumber(buy_max),
            solevel = solevel,
            server_ip = server_ip,
            server_port = server_port,
            table_type = tonumber(table_type),
            big_blind = tonumber(big_blind)
        }
        if t then
            v.db_info = t
        end
    end

    --log.info("robots=", robots)
    --log.info("robot_ids_t=", robot_ids_t)
end

--fixme
local function get_pool_agent()
    return skynet.newservice("service_socket_agent")
end

local function get_robot_agent(param_t)
    local robots = {}
    local counts = tonumber(param_t.num) 
    for i=1, counts do
        local robot_agent = get_pool_agent()
        if robot_agent then 
            local tmp = {
                agent = robot_agent,
                ai = param_t.ai,
                platid = param_t.platid,
                followuid = param_t.followuid,
                --svid = param_t.svid,
                --tid = param_t.tid,
                --robotid = param_t.robotid,
            }
            table.insert(robots, tmp)
        end 
    end

    return robots
end

--根据tid和followuid添加robot
local function get_robots(self, msg)
    if not msg.platid then 
        log.error("web get_robots no platid!")
        return 
    end
    if not msg.num then 
        log.error("web get_robots no nums!")
        return
    end

    local robots = get_robot_agent(msg)

    local svid, tid = cc.call_config("fill_web_info", tonumber(msg.platid),
        tonumber(msg.tid), tonumber(msg.followuid))
    if not svid or not tid then 
        log.error("fill_web_info svid:"..(svid or "nil").." tid:"..(tid or "nil"))
        return robots
    end
    
    local buy_min = cc.call_config("get_buy_min", tonumber(msg.platid), tonumber(svid), tonumber(tid))
    if not buy_min then 
        log.error("get_robots buy_min==nil!")
        return robots
    end

    fill_robot_info(robots, msg.platid, svid, tid, buy_min, msg.num)

    return robots
end

--fixme 根据服务器svid添加
local function get_robots_ext(self, msg)
    --fixme 
end

local function kick_robot_by_tid(t_use_robots, tid)
    local ret_t = {}
    
    for _, v in pairs(t_use_robots) do
        if tonumber(v.config_info.tid)==tonumber(tid) then 
            ret_t.platid = tonumber(v.platid)
            ret_t.svid = tonumber(v.config_info.svid)
            
            if not ret_t.agent_info then 
                ret_t.agent_info = {}
            end 
            table.insert(ret_t.agent_info, {
                agent = v.agent,
                robot_id = tonumber(v.db_info.id),
                tid = tonumber(v.config_info.tid)
            })

            v = nil
        end
    end

    return ret_t
end

local function kick_robot_by_robotid(t_use_robots, robot_id)
    local ret_t = {}
    
    for _, v in pairs(t_use_robots) do
        if tonumber(v.db_info.id)==tonumber(robot_id) then 
            ret_t.platid = tonumber(v.platid)
            ret_t.svid = tonumber(v.config_info.svid)

            if not ret_t.agent_info then 
                ret_t.agent_info = {}
            end
            table.insert(ret_t.agent_info, {
                agent = v.agent,
                robot_id = tonumber(v.db_info.id),
                tid = tonumber(v.config_info.tid)
            })

            v = nil
        end
    end

    return ret_t
end

local function kick_robot_by_followuid(t_use_robots, followuid, platid)
    local ret_t = {}

    local ret = cc.call_memcache("get_tid", "memcache_uid", platid, followuid)
    if not ret then 
        return ret_t
    end 

    for _, v in pairs(t_use_robots) do
        if tonumber(v.config_info.tid)==tonumber(ret) then 
            ret_t.platid = tonumber(v.platid)
            ret_t.svid = tonumber(v.config_info.svid)

            if not ret_t.agent_info then 
                ret_t.agent_info = {}
            end 
            table.insert(ret_t.agent_info, {
                agent = v.agent,
                robot_id = tonumber(v.db_info.id),
                tid = tonumber(v.config_info.tid)
            })
            
            v = nil
        end
    end

    return ret_t
end

local function kick_robot_by_svid(t_use_robots, svid)
    --fixme
end

--检测是否输了每日最大额度
local function check_robot_lose_max(msg)
    if tonumber(skynet.getenv("robots_lose_money_limit"))==nil then
        return
    end

    local svid, tid = cc.call_config("fill_web_info", tonumber(msg.platid),
        tonumber(msg.tid), tonumber(msg.followuid))

    local server_config = cc.call_config("get_server_config", tonumber(msg.platid), tonumber(svid), tonumber(tid))
    local table_type
    if server_config then
        local tables = (server_config or {}).tables or {}
        table_type = (tables[tid] or {}).table_type
    end

    if table_type==TABLE_TYPE.TARNEEB then
        local robot_lose_max = tonumber(skynet.getenv("robots_lose_money_limit"))
        local ret, value = cc.call_redis("get", "redis_gi", tonumber(msg.platid), "TARNEEB_ROBOT_TOTAL_LOSE")
        if ret==false then
            return
        end

        value = tonumber(value) or 0
        if value<0 and math.abs(value)>=robot_lose_max then
            log.warning("check_robot_lose_max true!", "value="..value.." |robot_lose_max="..robot_lose_max)
            return true
        end
    end
end

--============================= WEB MSG =============================--
function M:add(msg)
    if not msg
    or (not msg.platid) then
        log.error("web add error! msg=", msg) 
        return
    end
    if not msg.num then
        msg.num = 1
    end

    --延迟1~2s再进机器人
    local index = math.random(100, 200)
    skynet.sleep(index)

    local only_plat_id = tonumber(skynet.getenv("only_plat_id"))
    if only_plat_id 
    and  (only_plat_id~=tonumber(msg.platid)) then 
        log.error("web add invalid platid!  |only_plat_id="..only_plat_id.."  |msg.platid="..msg.platid)
        return
    end

    --判断每日机器人最大输钱
    if check_robot_lose_max(msg) then
        log.warning("check_robot_lose_max true! LAUNCH robot 0")
        return
    end

    local robots
    if not msg.svid then 
        --根据tid和followuid添加robot
        robots = get_robots(self, msg)
    else
        --fixme
        robots = get_robots_ext(self, msg)
    end
    --log.info("get_robots: ", robots)

    local success_index = 0
    local agent_connect = function()
        for _, v in pairs(robots or {}) do
            if v.db_info and v.db_info.id then 
                self.t_use_robots[tonumber(v.db_info.id)] = v
                skynet.call(v.agent, "lua", "connect_server", v)
                success_index = success_index + 1
            else
                if v.agent then
                    skynet.send(v.agent, "lua", "disconnect")
                end
            end
        end
    end
    Queue(agent_connect)

    log.warning("need launch ["..(msg.num or 0).."]".." | total launch ["..(success_index or 0).."] robot! LAUNCH...")
end

--kick
function M:kick(msg)
    --log.info("robot_manager kick robot! msg=", msg)
    --log.info("robot_manager kick robot! t_use_robots=", self.t_use_robots)

    local agent_info_t
    if msg.tid then 
        agent_info_t = kick_robot_by_tid(self.t_use_robots, tonumber(msg.tid))
    elseif msg.robotid then
        agent_info_t = kick_robot_by_robotid(self.t_use_robots, tonumber(msg.robotid))
    elseif msg.followuid then
        agent_info_t = kick_robot_by_followuid(self.t_use_robots, tonumber(msg.followuid), tonumber(msg.platid))
    else
        agent_info_t = kick_robot_by_svid(self.t_use_robots, tonumber(msg.svid))
    end

    if agent_info_t==nil
    or agent_info_t.agent_info==nil then 
        log.error("robot_manager kick robot error! agent_info_t=", agent_info_t)
        return
    end

    for _, v in pairs(agent_info_t.agent_info) do
        skynet.send(v.agent, "lua", "disconnect_server", v.agent)
    end
end

--后台更新塔尼布叫分配置
function M:call(msg)
    log.info("backstage message : ", msg)
    if not msg.platid then 
        return
    end
    local f = io.open("./config/backstage_config_call_score_"..msg.platid..".lua", "w+")
    if f then 
        local serpent = require "serpent"
        msg.cmd = nil
        msg.platid = nil
        msg.tid = nil
        f:write("local backstage_config_call_score=", serpent.block(msg))
        f:write("\n\nreturn backstage_config_call_score")
        f:close()
    end
end

function M:on_disconnect_agent(agent)
    local select_agent 
    for _, v in pairs(self.t_use_robots) do
        if tonumber(v.agent)==tonumber(agent) then 
            select_agent = v
        end
    end
    if select_agent then 
        self.t_use_robots[tonumber(select_agent.db_info.id)] = nil
        cc.call_config("kick_robot", select_agent.db_info.id, select_agent.platid)
        --log.info("finish close_robot t_use_robots=", self.t_use_robots)
    else
        log.error("on_disconnect_agent no find! agent=", agent)
    end
end

function M:web_ctrl_msg(msg)
    log.warning("web message : ", msg)
    if not msg.cmd then
        msg.cmd = "add"
    end

    local f = M[msg.cmd]
    if f then
        f(M, msg)
    else
        log.error("Unknown web_ctrl_msg CMD: ", msg)
    end
end

--============================= debug =============================--
function M:debug_get_user_money(platid, user_id)
    local money = cc.call_memdb("get_money", tonumber(platid), tonumber(user_id))
    log.warning("debug_get_user_money money=", money)
end

function M:debug_get_watchdog_infos()
    skynet.call(".csocket_watchdog", "debug_get_infos")
end

function M:debug_get_gate_infos()
    skynet.call(".csocket_watchdog", "debug_cgate_infos")
end

function M:debug_get_robot_manager_infos()
    log.warning("robot_manager.t_use_robots=", self.t_use_robots)
end

--============================= Init =============================--
function M:init()
    --register
    skynet.register(".robot_manager")

    --watchdog
    self.watchdog = skynet.newservice("service_socket_watchdog")

    --debug_console
    local node_name = skynet.getenv("node_name")
    local index = tonumber(nn[node_name])
    skynet.newservice("debug_console", index + 2000)
end

skynet.start(function ()
    skynet.dispatch("lua", function(session, address, cmd, ...)
        local f = M[cmd]
        if f then
            skynet.ret(skynet.pack( f(M, ...)) )
        else
            error(string.format("Unknown command %s", tostring(cmd)))
        end
    end)

    M:init()
end)

return M